package samples;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

import AG.DNA;
import agent.AgentBoard;
import agent.AgentHand;
import agent.DominoAgent;
import core.basic.Movement;
import core.basic.Piece;

//290.0 0.780308303997753 0.3396564740834931 0.8107476084855044 0.46479296275452964 0.6603116206296763 0.2244697971522293 0.6168128668112327 0.3083409336310672 0.041405386946001155 0.9971692207273857 0.7205457070559431 0.757634313637039 0.46757552982295897 0.5714006453058194 
//trained to beat three WithDNA1
public class WithDNA2 implements DominoAgent{

	private DNA dna;
	private static final int cs = 14;

	private AgentHand hand;
	private AgentBoard board;

	public WithDNA2() {
		double DNACode[] = new double[]{0.780308303997753, 0.3396564740834931, 0.8107476084855044, 0.46479296275452964, 0.6603116206296763, 0.2244697971522293, 0.6168128668112327, 0.3083409336310672, 0.041405386946001155, 0.9971692207273857, 0.7205457070559431, 0.757634313637039, 0.46757552982295897, 0.5714006453058194};
		this.dna = new DNA(DNACode);
	}

	@Override
	public Movement getMovement(AgentHand yourHand, AgentBoard currentBoard) {
		this.hand = yourHand;
		this.board = currentBoard;
		ArrayList<Movement> moves = combine();

		for (Movement m : moves) {
			if (currentBoard.canMake(m)) {
				return m;
			}
		}

		return new Movement();//ATEMCAO
	}

	private ArrayList<Movement> combine() {
		Map<Movement, Double> map = new HashMap<Movement, Double>();
		for (Piece p : hand) {
			Movement m = new Movement();
			m.pass = false;
			m.p = p;
			m.side = AgentBoard.LEFT;
			map.put(m, 0.0);

			m = new Movement();
			m.pass = false;
			m.p = p;
			m.side = AgentBoard.RIGHT;
			map.put(m, 0.0);
		}
		for (int i = 0; i < cs; i++) {
			Map<Movement, Double> mMap = callc(i);
			for (Movement m : mMap.keySet()) {
				double av = map.get(m).doubleValue();
				av += mMap.get(m)*dna.getGene(i);
				map.put(m, new Double(av));
			}
		}
		ArrayList<Movement> pieces = new ArrayList<Movement>(map.keySet());
		Collections.sort(pieces, new SmallerSetValueComparator(new HashMap<Object, Double>(map)));
		return pieces;
	}
	private Map<Movement, Double> translate(Map<Piece, Double> map) {
		Map<Movement, Double> res = new HashMap<Movement, Double>();

		for (Piece p : map.keySet()) {
			Movement m = new Movement();
			m.pass = false;
			m.side = AgentBoard.LEFT;
			m.p = p;
			res.put(m, map.get(p));

			m = new Movement();
			m.pass = false;
			m.side = AgentBoard.RIGHT;
			m.p = p;
			res.put(m, map.get(p));
		}

		return res;
	}

	private Map<Movement, Double> callc(int i){
		switch (i) {
		case 0:
			return c0();
		case 1:
			return c1();
		case 2:
			return c2();
		case 3:
			return c3();
		case 4:
			return c4();
		case 5:
			return c5();
		case 6:
			return c6();
		case 7:
			return c7();
		case 8:
			return c8();
		case 9:
			return c9();
		case 10:
			return c10();
		case 11:
			return c11();
		case 12:
			return c12();
		case 13:
			return c13();
		default:
			break;
		}
		return null;
	}
	@Override
	public void receiveInfo(Movement m, DominoAgent playerAgent) {
		// TODO Auto-generated method stub

	}

	@Override
	public Movement wrongMovement(Movement wrongMovement) {
		// TODO Auto-generated method stub
		return null;
	}

	//carroças tem MAIOR chance	
	private Map<Movement, Double> c0(){
		Map<Piece, Double> res = new HashMap<Piece, Double>();
		for (Piece piece : hand) {
			double value = (piece.getLeft() == piece.getRight()) ? 1.0 : 0.0;
			res.put(piece, new Double(value));
		}
		return translate(res);
	}

	//carroças tem MENOR chance
	private Map<Movement, Double> c1(){
		Map<Piece, Double> res = new HashMap<Piece, Double>();
		for (Piece piece : hand) {
			double value = (piece.getLeft() == piece.getRight()) ? 0.0 : 1.0;
			res.put(piece, new Double(value));
		}
		return translate(res);
	}

	//maior peca tem maior chance linear
	private Map<Movement, Double> c2(){
		Map<Piece, Double> res = new HashMap<Piece, Double>();
		ArrayList<Piece> pieces = new ArrayList<Piece>();
		for (Piece p : hand) {
			pieces.add(p);
		}
		Collections.sort(pieces, new BiggerSumComparator());
		for (int i = 0; i < pieces.size(); i++) {
			res.put(pieces.get(i), (i+1.0)/(pieces.size()+0.0));
		}
		return translate(res);
	}

	//menor peca tem maior chance linear
	private Map<Movement, Double> c3(){
		Map<Piece, Double> res = new HashMap<Piece, Double>();
		ArrayList<Piece> pieces = new ArrayList<Piece>();
		for (Piece p : hand) {
			pieces.add(p);
		}
		Collections.sort(pieces, new SmallerSumComparator());
		for (int i = 0; i < pieces.size(); i++) {
			res.put(pieces.get(i), (i+1.0)/(pieces.size()+0.0));
		}
		return translate(res);
	}

	//maior peca com maior chance normalizada
	private Map<Movement, Double> c4(){
		Map<Piece, Double> res = new HashMap<Piece, Double>();
		for (Piece piece : hand) {
			double value = ((double)(piece.getLeft() + piece.getRight()))/12.0;
			res.put(piece, new Double(value));
		}
		return translate(res);
	}

	//menor paca tem maior chance normalizada
	private Map<Movement, Double> c5(){
		Map<Piece, Double> res = new HashMap<Piece, Double>();
		for (Piece piece : hand) {
			double value = 1.0 - ((double)(piece.getLeft() + piece.getRight()))/12.0;
			res.put(piece, new Double(value));
		}
		return translate(res);
	}

	//peca com o valor que mais saiu tem maior chance normalizado
	private Map<Movement, Double> c6() {
		Map<Piece, Double> res = new HashMap<Piece, Double>();
		for (Piece piece : hand) {
			double value = 0.0;
			for (Piece piece2 : board) {
				if (piece2.getLeft() == piece.getLeft() || piece2.getRight() == piece.getLeft() ||
						piece2.getLeft() == piece.getRight() || piece2.getRight() == piece.getRight()) {
					value+=1.0;
				}
			}
			res.put(piece, new Double(value));
		}
		for (Piece piece : res.keySet()) {
			res.put(piece, (res.get(piece)/(board.size()+0.0)));
		}
		return translate(res);
	}

	//peca com o valor que menos saiu tem maior chance normalizado
	private Map<Movement, Double> c7() {
		Map<Piece, Double> res = new HashMap<Piece, Double>();
		for (Piece piece : hand) {
			double value = 0.0;
			for (Piece piece2 : board) {
				if (piece2.getLeft() == piece.getLeft() || piece2.getRight() == piece.getLeft() ||
						piece2.getLeft() == piece.getRight() || piece2.getRight() == piece.getRight()) {
					value+=1.0;
				}
			}
			res.put(piece, new Double(value));
		}
		for (Piece piece : res.keySet()) {
			res.put(piece, 1.0-(res.get(piece)/(board.size()+0.0)));
		}
		return translate(res);
	}

	//peca com o valor que mais saiu tem maior chance linear
	private Map<Movement, Double> c8() {
		Map<Piece, Double> res = new HashMap<Piece, Double>();
		for (Piece piece : hand) {
			double value = 0.0;
			for (Piece piece2 : board) {
				if (piece2.getLeft() == piece.getLeft() || piece2.getRight() == piece.getLeft() ||
						piece2.getLeft() == piece.getRight() || piece2.getRight() == piece.getRight()) {
					value+=1.0;
				}
			}
			res.put(piece, new Double(value));
		}
		ArrayList<Piece> pieces = new ArrayList<Piece>(res.keySet());
		Collections.sort(pieces, new BiggerSetValueComparator(new HashMap<Object, Double>(res)));
		for (int i = 0; i < pieces.size(); i++) {
			res.put(pieces.get(i), (i+1.0)/(pieces.size()+0.0));
		}
		return translate(res);
	}

	//peca com o valor que menos saiu tem maior chance linear
	private Map<Movement, Double> c9() {
		Map<Piece, Double> res = new HashMap<Piece, Double>();
		for (Piece piece : hand) {
			double value = 0.0;
			for (Piece piece2 : board) {
				if (piece2.getLeft() == piece.getLeft() || piece2.getRight() == piece.getLeft() ||
						piece2.getLeft() == piece.getRight() || piece2.getRight() == piece.getRight()) {
					value+=1.0;
				}
			}
			res.put(piece, new Double(value));
		}
		ArrayList<Piece> pieces = new ArrayList<Piece>(res.keySet());
		Collections.sort(pieces, new SmallerSetValueComparator(new HashMap<Object, Double>(res)));
		for (int i = 0; i < pieces.size(); i++) {
			res.put(pieces.get(i), (i+1.0)/(pieces.size()+0.0));
		}
		return translate(res);
	}

	//peca com o valor mais presente na mao tem maior chance normalizado
	private Map<Movement, Double> c10() {
		Map<Piece, Double> res = new HashMap<Piece, Double>();
		for (Piece piece : hand) {
			double value = 0.0;
			for (Piece piece2 : hand) {
				if (piece2.getLeft() == piece.getLeft() || piece2.getRight() == piece.getLeft() ||
						piece2.getLeft() == piece.getRight() || piece2.getRight() == piece.getRight()) {
					value+=1.0;
				}
			}
			res.put(piece, new Double(value));
		}
		for (Piece piece : res.keySet()) {
			res.put(piece, (res.get(piece)/(board.size()+0.0)));
		}
		return translate(res);
	}

	//peca com o valor menos presente na mao tem maior chance normalizado
	private Map<Movement, Double> c11() {
		Map<Piece, Double> res = new HashMap<Piece, Double>();
		for (Piece piece : hand) {
			double value = 0.0;
			for (Piece piece2 : board) {
				if (piece2.getLeft() == piece.getLeft() || piece2.getRight() == piece.getLeft() ||
						piece2.getLeft() == piece.getRight() || piece2.getRight() == piece.getRight()) {
					value+=1.0;
				}
			}
			res.put(piece, new Double(value));
		}
		for (Piece piece : res.keySet()) {
			res.put(piece, 1.0-(res.get(piece)/(board.size()+0.0)));
		}
		return translate(res);
	}

	//peca com o valor mais presente na mao tem maior chance linear
	private Map<Movement, Double> c12() {
		Map<Piece, Double> res = new HashMap<Piece, Double>();
		for (Piece piece : hand) {
			double value = 0.0;
			for (Piece piece2 : hand) {
				if (piece2.getLeft() == piece.getLeft() || piece2.getRight() == piece.getLeft() ||
						piece2.getLeft() == piece.getRight() || piece2.getRight() == piece.getRight()) {
					value+=1.0;
				}
			}
			res.put(piece, new Double(value));
		}
		ArrayList<Piece> pieces = new ArrayList<Piece>(res.keySet());
		Collections.sort(pieces, new BiggerSetValueComparator(new HashMap<Object, Double>(res)));
		for (int i = 0; i < pieces.size(); i++) {
			res.put(pieces.get(i), (i+1.0)/(pieces.size()+0.0));
		}
		return translate(res);
	}

	//peca com o valor menos presente na mao tem maior chance linear
	private Map<Movement, Double> c13() {
		Map<Piece, Double> res = new HashMap<Piece, Double>();
		for (Piece piece : hand) {
			double value = 0.0;
			for (Piece piece2 : hand) {
				if (piece2.getLeft() == piece.getLeft() || piece2.getRight() == piece.getLeft() ||
						piece2.getLeft() == piece.getRight() || piece2.getRight() == piece.getRight()) {
					value+=1.0;
				}
			}
			res.put(piece, new Double(value));
		}
		ArrayList<Piece> pieces = new ArrayList<Piece>(res.keySet());
		Collections.sort(pieces, new SmallerSetValueComparator(new HashMap<Object, Double>(res)));
		for (int i = 0; i < pieces.size(); i++) {
			res.put(pieces.get(i), (i+1.0)/(pieces.size()+0.0));
		}
		return translate(res);
	}

	class BiggerSetValueComparator implements Comparator<Object> {
		private Map <Object, Double> map;
		public BiggerSetValueComparator(Map <Object, Double> map) {
			this.map = map;
		}
		@Override
		public int compare(Object o1, Object o2) {
			return (map.get(o1) - map.get(o2)) > 0.0 ? 1 : -1;
		}
	}

	class SmallerSetValueComparator implements Comparator<Object> {
		private Map <Object, Double> map;
		public SmallerSetValueComparator(Map <Object, Double> map) {
			this.map = map;
		}
		@Override
		public int compare(Object o1, Object o2) {
			return (map.get(o1) - map.get(o2)) < 0.0 ? 1 : -1;
		}
	}

	class BiggerSumComparator implements Comparator<Piece> {

		@Override
		public int compare(Piece o1, Piece o2) {
			return o1.getPoints()-o2.getPoints();
		}

	}

	class SmallerSumComparator implements Comparator<Piece> {

		@Override
		public int compare(Piece o1, Piece o2) {
			return o2.getPoints()-o1.getPoints();
		}

	}
}
